package com.tempjob.common.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author hui
 * @Date 2023/4/12 17:35
 **/
public class RecommenderSystem {

    private Map<String, Map<String, Double>> userItemRatingsMap;

    public RecommenderSystem(Map<String, Map<String, Double>> userItemRatingsMap) {
        this.userItemRatingsMap = userItemRatingsMap;
    }

    public List<String> recommendItems(String user, int numRecommendations) {
        Map<String, Double> itemScores = new HashMap<>();

        // calculate item scores based on matching weights
        for (String item : userItemRatingsMap.get(user).keySet()) {
            for (String otherUser : userItemRatingsMap.keySet()) {
                if (!otherUser.equals(user)) {
                    double rating = getUserRating(otherUser, item);
                    double weight = calculateMatchingWeight(user, otherUser);
                    double weightedRating = rating * weight;
                    if (!itemScores.containsKey(item)) {
                        itemScores.put(item, weightedRating);
                    } else {
                        itemScores.put(item, itemScores.get(item) + weightedRating);
                    }
                }
            }
        }

        // sort items by score in descending order and return the top recommendations
        List<String> recommendations = new ArrayList<>(itemScores.keySet());
        recommendations.sort((item1, item2) -> Double.compare(itemScores.get(item2), itemScores.get(item1)));
        return recommendations.subList(0, Math.min(numRecommendations, recommendations.size()));
    }

    private double calculateMatchingWeight(String user1, String user2) {
        Map<String, Double> ratings1 = userItemRatingsMap.get(user1);
        Map<String, Double> ratings2 = userItemRatingsMap.get(user2);

        double sumOfSquares = 0.0;
        for (String item : ratings1.keySet()) {
            if (ratings2.containsKey(item)) {
                sumOfSquares += Math.pow(ratings1.get(item) - ratings2.get(item), 2);
            }
        }
        return 1 / (1 + Math.sqrt(sumOfSquares));
    }

    private double getUserRating(String user, String item) {
        return userItemRatingsMap.get(user).containsKey(item) ? userItemRatingsMap.get(user).get(item) : 0.0;
    }

}
